/*
 * @(#)SystemMonitorFilter.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework.web;

import java.io.IOException;
import java.sql.Connection;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import com.dcivision.framework.Crypt;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.ProtectedFilterHelperFactory;
import com.dcivision.framework.ProtectedSourceManager;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.Utility;
import com.dcivision.framework.bean.ProtectedResource;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
//import com.dcivision.framework.web.AbstractAction;
/**
 * Filter to protected task , check user input password
 *
 * @author Dick xie
 * @company DCIVision Limited
 * @creation date 18/03/2005
 * @version $Revision: 1.11.2.1 $
 */
public class ProtectedResourceFilter implements Filter {

  protected FilterConfig config;
  private static final String defaultHelperClass = DefaultProtectedFilterHelper.class.getName();

  protected Log log = new LogFactoryImpl().getInstance(this.getClass());
  protected static String FORM_SIGNON_URL = "Authenticate.do";
  //protected static String LOGIN_PAGE = "Login.do";
  protected static String AUTHENTICATE_FAILED = "authenticatefailed";

  /**
   * Take this filter out of service.
   */
  public void destroy() {
    try {
log.debug(this.getClass().getName()+" destroy()");
    } catch (Exception ex) {
      log.error(ex, ex);
    } finally {
      // do nothing
    }
  }

  /**
   * Select and set (if specified) the character encoding to be used to
   * interpret request parameters for this request.
   *
   * @param request The servlet request we are processing
   * @param result The servlet response we are creating
   * @param chain The filter chain we are processing
   *
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet error occurs
   */
  public  void doFilter(ServletRequest request, ServletResponse  response,
    FilterChain chain)  throws IOException, ServletException {
      HttpServletRequest hreq = (HttpServletRequest)request;
      HttpServletResponse hres = (HttpServletResponse)response;

      this.setDefaultEncoding(hreq, hres);

      // init db conn;
      Connection conn = null;
      try {
        // check user is or not login
        if (Utility.isEmpty(this.getSessionContainer(hreq).getUserRecordID())) {
          chain.doFilter(request,response);
          return;
        }

        conn = DataSourceFactory.getConnection();

        String currentURI = hreq.getRequestURL().toString();
        String currentURL = hreq.getRequestURI();
        // get everything after the context root
        int firstSlash = currentURL.indexOf("/",1); // jump past the starting slash
        String targetURL = null;
        if (firstSlash != -1) targetURL = currentURL.substring(firstSlash + 1,
        currentURL.length());

        String signOnURL = targetURL;
        if (signOnURL.indexOf("/") >= 0) {
          signOnURL = signOnURL.substring(signOnURL.indexOf("/") + 1,
          signOnURL.length());
       }
        String passwordStr = hreq.getParameter("loginPwd");
       if ((signOnURL != null) && !Utility.isEmpty(passwordStr)) {
         validateSignOn(request, response, chain, conn);
         // jump out of this method
         return;
      }

      ProtectedSourceManager protectedSourceManager = new ProtectedSourceManager(this.getSessionContainer(hreq), conn);
      List protectedSourceList = protectedSourceManager.getPropectedResource(targetURL);
      if (!Utility.isEmpty(protectedSourceList)){
        String currentHelperClass = null;
        ProtectedResource protectedResource = (ProtectedResource)protectedSourceList.get(0);
        if (!Utility.isEmpty((protectedResource).getHelperClass())) {
          currentHelperClass = protectedResource.getHelperClass();
        } else {
          currentHelperClass = defaultHelperClass;
        }

        Class c = Class.forName(currentHelperClass);
        log.debug("helper class = >>>>>>" + c.getName());
        ProtectedFilterHelper helperClass = ProtectedFilterHelperFactory.getInstance(protectedSourceList, this.getSessionContainer(hreq), conn);
        hreq.getSession().setAttribute("ORIGINAL_URL",  targetURL);
        if (helperClass.isProtected(hreq)) {
         // hreq.getSession().setAttribute("sourceID", protectedSource.getID());
          // save the url parameter to session;
          /*
          if (!Utility.isEmpty(hreq.getParameterNames())) {
            //hreq.getSession().setAttribute("paramNames", Collections.list(hreq.getParameterNames()));
            //log.debug("this.collections size is   " + Collections.list(hreq.getParameterNames()).size());
            Map reqParametersMap = new HashMap();
            for(java.util.Enumeration e = hreq.getParameterNames(); e.hasMoreElements();) {
              String paramName = (String)e.nextElement();
              String[] parameterValues = request.getParameterValues(paramName);
              reqParametersMap.put(paramName, parameterValues);
            }
            hreq.getSession().setAttribute("reqParametersMap", reqParametersMap);
          }
          */
          //String url = hreq.getContextPath() + "/" + FORM_SIGNON_URL;
          if("workflow/MaintWorkflowTask.do".equals(targetURL)){
            String tokenForThePost=request.getParameter("MaintWorkflowTaskProtectedToken");
            String tokenForSave=(String) hreq.getSession().getAttribute("MaintWorkflowTaskProtectedToken");
            if(tokenForThePost!=null&&tokenForThePost.equals(tokenForSave)){
              hreq.getSession().removeAttribute("MaintWorkflowTaskProtectedToken");
              chain.doFilter(request, response);
              return;
            }
            if(tokenForThePost==null){
              hreq.getSession().setAttribute("MaintWorkflowTaskProtectedToken", ""+System.currentTimeMillis());
            }
          }
          config.getServletContext().getRequestDispatcher("/" + FORM_SIGNON_URL).forward(request, response);

          //hres.sendRedirect(url);
          // Jump out of the filter and go to the next page
          return;
        }
      }    // No matches if we made it to here
      chain.doFilter(request,response);
    } catch (Exception ex) {
      log.error(ex, ex);
    } finally {
      try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
    }
  }

  protected SessionContainer getSessionContainer(HttpServletRequest request) {
    SessionContainer ctx = (SessionContainer)request.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if (ctx==null) {
      ctx = new SessionContainer();
      request.getSession().setAttribute(GlobalConstant.SESSION_CONTAINER_KEY, ctx);
    }
    return(ctx);
  }

  /* (non-Javadoc)
   * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
   */
  public void init(FilterConfig arg0) throws ServletException {
log.debug(this.getClass().getName()+" init()");
    this.config = arg0;
  }


  public  void validateSignOn(ServletRequest request, ServletResponse  response, FilterChain chain, Connection conn) throws IOException, ServletException {
    // convert to a http servlet request for now
    HttpServletRequest hreq = (HttpServletRequest)request;
    ProtectedSourceManager protectedSourceManager = null;

    try {
      protectedSourceManager = new ProtectedSourceManager(this.getSessionContainer(hreq), conn);
      UserRecordDAObject userRecordDAO = new UserRecordDAObject(this.getSessionContainer(hreq), conn);

      HttpServletResponse hres = (HttpServletResponse)response;
      // get the password
      String password =  hreq.getParameter("loginPwd");
      password = Crypt.encrypt(password, SystemParameterFactory.getSystemParameter(SystemParameterConstant.CRYPTO_SALT));
      log.debug("Crypt after password:::::::" + password);
      Integer sourceID = (Integer)hreq.getSession().getAttribute("sourceID");
      Integer objectValue = (Integer)hreq.getSession().getAttribute("Current_Protected_Object");
      boolean authenticated = false;
      if (!Utility.isEmpty(protectedSourceManager.getProtection(sourceID, objectValue))) {
        if (password.equals(protectedSourceManager.getProtection(sourceID, objectValue))) {
          // place a true boolean in the session
          // redirect to the original destination
          String targetURL = (String)hreq.getSession().getAttribute("ORIGINAL_URL");
          //hres.sendRedirect(hreq.getContextPath() + "/" + targetURL);
          //String parameterStr = this.getParametersStr(hreq);
          //if (!Utility.isEmpty(parameterStr)) {
          //  targetURL += parameterStr;
         // }
          log.debug("The targetURL is :::::::" + targetURL);
          config.getServletContext().getRequestDispatcher("/" + targetURL).forward(request, response);
          //chain.doFilter(request,response);
          return;
        } else {
          //addError(hreq, WRONG_PASSWORD);
          hreq.setAttribute("AUTHENTICATE_FAILED", AUTHENTICATE_FAILED);
          config.getServletContext().getRequestDispatcher("/" + FORM_SIGNON_URL).forward(request, response);
          return;
        }
      } else {
        UserRecord userRecord = (UserRecord)userRecordDAO.getObjectByID(this.getSessionContainer(hreq).getUserRecordID());
        if (password.equals(userRecord.getLoginPwd())) {
          // place a true boolean in the session
          // redirect to the original destination
          String targetURL = (String)hreq.getSession().getAttribute("ORIGINAL_URL");
          //hres.sendRedirect(hreq.getContextPath() + "/" + targetURL);
         // String parameterStr = this.getParametersStr(hreq);
          //if (!Utility.isEmpty(parameterStr)) {
          //  targetURL += parameterStr;
          //}
          log.debug("The targetURL is :::::::" + targetURL);
          config.getServletContext().getRequestDispatcher("/" + targetURL).forward(request, response);
          //chain.doFilter(request,response);
          return;
        } else {
          //addError(hreq, WRONG_PASSWORD);
          hreq.setAttribute("AUTHENTICATE_FAILED", AUTHENTICATE_FAILED);
          config.getServletContext().getRequestDispatcher("/" + FORM_SIGNON_URL).forward(request, response);
          return;
        }
      }
    } catch (Exception ex) {
      log.error(ex, ex);
    }
  }
 /*
  public String getParametersStr(HttpServletRequest hreq) {
    StringBuffer paraStr = new StringBuffer();
    //List e = (List)hreq.getSession().getAttribute("paramNames");
    Map parametersMap = (Map)hreq.getSession().getAttribute("reqParametersMap");
    if (!Utility.isEmpty(parametersMap)) {
      Iterator iterator = parametersMap.keySet().iterator();
      for (int i = 0 ; iterator.hasNext(); i++) {
        String currentParaKey = (String)iterator.next();
        log.debug("the " + i + "key is " + currentParaKey + "( value is )" +  ((String[])parametersMap.get(currentParaKey))[0]);
        if (i == 0) {
          paraStr.append("?" + currentParaKey + "=" + ((String[])parametersMap.get(currentParaKey))[0]);
        } else {
          paraStr.append("&" + currentParaKey + "=" + ((String[])parametersMap.get(currentParaKey))[0]);
        }
      }
      log.debug("the parameters is ::::::;" + paraStr.toString());
      return paraStr.toString();
    }
    return null;
  }
  */

  /**
   * setDefaultEncoding
   *
   * Set the Default Encoding for the whole application.
   *
   * @param request   HTTP request
   * @param response  HTTP response
   */
  protected void setDefaultEncoding(HttpServletRequest request, HttpServletResponse response) {
    String encoding = SystemParameterFactory.getSystemParameter(SystemParameterConstant.ENCODING);
    String requestURL=(request.getRequestURL()==null?"":request.getRequestURL().toString());
    if(requestURL.indexOf("form/GenerateXML.do")>0){
      encoding="GBK";
    }
    try {
      if (encoding != null) {
        if (request instanceof org.apache.struts.upload.MultipartRequestWrapper) {
          ((org.apache.struts.upload.MultipartRequestWrapper)request).getRequest().setCharacterEncoding(encoding);
        } else {
          request.setCharacterEncoding(encoding);
        }
      }
    } catch (Exception e) {
      log.error("Unable To Set Character Encoding for \"" + encoding + "\"", e);
    }
  }

}